#include "log.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <string>
#include <chrono>
#include <thread>

using namespace std;

typedef struct
{
    struct tm tm_info;
    long milliseconds;
} time_with_ms;

static string lv_str[MAX_INDEX] = {"DEBUG", "INFO", "ERROR"};

inline void get_current_time_with_ms(string &date, string &time)
{
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);

    struct tm local_tm;
    localtime_r(&ts.tv_sec, &local_tm);
    long milliseconds = ts.tv_nsec / 1000000L;

    char date_str[64] = "";
    sprintf(date_str, "%04d-%02d-%02d",
            local_tm.tm_year + 1900,
            local_tm.tm_mon + 1,
            local_tm.tm_mday);
    date = date_str;

    char time_str[64] = "";
    sprintf(time_str, "%02d:%02d:%02d.%03ld",
            local_tm.tm_hour,
            local_tm.tm_min,
            local_tm.tm_sec, milliseconds);
    time = time_str;

    return;
}

Clog::Clog() : level(0), running(0), filename(), fp(nullptr), queue(8, true) {};

Clog::~Clog()
{
    if(fp)
        fclose(fp);
    return;
}

void Clog::write_log_asyn(string str, int level)
{
    if (level < this->level)
        return;
    string date = "", time = "";
    LogData logData;

    get_current_time_with_ms(date, time);

    logData.date = date;
    logData.level = level;
    logData.data = date + " " + time +" "+lv_str[level]+" "+str;
    this->queue.push_task(logData);
    return;
}

void Clog::write_log_sync(string str, int level)
{
   write_log_asyn(str, level);
   do_write_log();
}

int Clog::do_write_log()
{
    LogData logData;
    int ret = this->queue.get_task2(logData);
    if (ret != 0)
    {
        return -1;
    }

    if (logData.date != this->today)
    {
        today = logData.date;
        if (fp)
        {
            fclose(fp);
            fp = nullptr;
        }

        if (this->path.length()!=0 && this->path.at(path.size() - 1) != '/')
            path.append("/");

        string fullname = path + today + "_" + filename + ".txt";
        fp = fopen(fullname.c_str(), "a+");
        if (!fp)
        {
            fprintf(stderr, "fopen error:%s\n", strerror(errno));
            return -2;
        }
    }

    if (fp)
    {
        fprintf(fp, "%s", logData.data.c_str());
        fflush(fp);
    }
}

void Clog::recv_thread()
{
    while (1)
    {
        if (this->queue.get_size() == 0)
        {
           std::this_thread::sleep_for(std::chrono::seconds(1));
        }
        else
        {
           do_write_log();
        }
    }
}

void Clog::start_thread()
{
    if (this->running == 1)
        return;
    this->running = 1;
    std::thread tid = std::thread(&Clog::recv_thread, this);
    tid.detach();
    return;
}
